{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "slide_helper": "subslide_end",
     "slide_type": "subslide"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "\n",
    "# Data Science in Python (DSiP) - A short introduction to Numpy\n",
    "\n",
    "\n",
    "by [Michael Granitzer (michael.granitzer@uni-passau.de)](http://www.mendeley.com/profiles/michael-granitzer/) \n",
    "and [Konstantin Ziegler (konstantin.ziegler@uni-passau.de)](http://zieglerk.net)\n",
    "\n",
    "based on the following sources\n",
    "\n",
    "* [Marcel Caraciolo](https://github.com/marcelcaraciolo), \n",
    "  [Big Data Tutorial](https://github.com/marcelcaraciolo/big-data-tutorial)\n",
    "* [J.R. Johansson (robert@riken.jp)](http://dml.riken.jp/~rob/), \n",
    "  [Scientific Programming in Pyton](http://github.com/jrjohansson/scientific-python-lectures)\n",
    "\n",
    "__License__\n",
    "\n",
    "This work is licensed under a [Creative Commons Attribution 3.0 Unported License](http://creativecommons.org/licenses/by/3.0/)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "slide_helper": "subslide_end",
     "slide_type": "subslide"
    },
    "slide_helper": "slide_end",
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Content\n",
    "1. Overview\n",
    "2. Numpy's Basic Data Structure - Multidimensional Arrays\n",
    "   1. Array Creation \n",
    "   1. Properties of Arrays\n",
    "   2. File I/O\n",
    "3. Slicing and Indexing Arrays\n",
    "4. Operations on numpy Arrays\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Overview"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_number": 3
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "## What is Numpy?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 4,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "A Python library that provides \n",
    "\n",
    "* a multidimensional array object\n",
    "* various derived objects (such as masked arrays and matrices)\n",
    "* and an assortment of routines for fast operations on arrays, e.g. \n",
    "  * mathematical, logical, shape\n",
    "  * manipulation, sorting, selecting\n",
    "  * I/O, discrete Fourier transforms\n",
    "  * basic linear algebra, basic statistical operations, \n",
    "  * random simulation \n",
    "  * and much more"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 4,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Numpy vs. Build-in Lists"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 6,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Why not simply use Python lists for computations instead of using new multidimensional arrays? \n",
    "\n",
    "There are several reasons:\n",
    "\n",
    "* Python lists are very general. They can contain any kind of object. They are dynamically typed. They do not support mathematical functions such as matrix and dot multiplications, etc. Implementating such functions for Python lists would not be very efficient because of the dynamic typing.\n",
    "* Numpy arrays are **statically typed** and **homogeneous**. The type of the elements is determined when array is created.\n",
    "* Numpy arrays are memory efficient.\n",
    "* Because of the static typing, fast implementation of mathematical functions such as multiplication and addition of `numpy` arrays can be implemented in a compiled language (C and Fortran is used).\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 6,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 8,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "slide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "#import numpy here\n",
    "import numpy as np\n",
    "\n",
    "# set some print options\n",
    "np.set_printoptions(precision=4)\n",
    "np.set_printoptions(threshold=5)\n",
    "np.set_printoptions(suppress=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 8,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "#  Numpy's basic data structure: the ndarray"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 10
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "\n",
    "\n",
    "* An Numpy `ndarray` is a multidimensional array object \n",
    "* Every array entry must correspond to preset data types (simple types like float, int etc. or complex types like strings, tupels)\n",
    "* an `ndarray` acts as container for data to be passed between algorithms\n",
    "* libraries written in a lower-level language, such as C or Fortran, can operate on the data stored in a NumPy array without copying any data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 11,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 9, 5, 4, 3])"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "# build an array using the array function\n",
    "arr = np.array([0, 9, 5, 4, 3])\n",
    "arr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 11,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Array creation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 13
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "There are several functions that are used to create new arrays:\n",
    "\n",
    "* from a Python list or tuples\n",
    "* using functions that are dedicated to generating numpy arrays, such as `arange`, `linspace`, etc.\n",
    "* reading data from files"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 14
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.,  0.,  0.,  0.])"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#returns an array with zeros\n",
    "np.zeros(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 15
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1.,  1.,  1.,  1.])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#returns an array with ones\n",
    "np.ones(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 16
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1.,  1.,  1.,  1.])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#returns an empty, non initalized array\n",
    "np.empty(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 17
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#similar to range\n",
    "np.arange(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 18
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 0, 0],\n",
       "       [0, 2, 0],\n",
       "       [0, 0, 3]])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# a diagonal matrix\n",
    "np.diag([1,2,3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 19
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 0, 0],\n",
       "       [0, 0, 2, 0],\n",
       "       [0, 0, 0, 3],\n",
       "       [0, 0, 0, 0]])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# diagonal with offset from the main diagonal\n",
    "np.diag([1,2,3], k=1) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 20
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# a vector: the argument to the array function is a Python list\n",
    "v = np.array([1,2,3,4])\n",
    "v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 21,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# a matrix: the argument to the array function is a nested Python list\n",
    "M = np.array([[1, 2], [3, 4]])\n",
    "M"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 21,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Type, size and shape of an array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 23,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "\n",
    "* all elements of an `ndarray` are of the same type. \n",
    "* The `ndarray.dtype` property is an attribute that specifies the data type\n",
    "of each element. \n",
    "* The `ndarray.shape` property is a tuple that indicates the size of each\n",
    "dimension.\n",
    "* The `ndarray.size` proprety indicates the number of elements in the array"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 23,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "**Examples**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 25
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.4168, -0.0563, -2.1362,  1.6403, -1.7934])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# init random gen\n",
    "np.random.seed(2)\n",
    "\n",
    "arr = np.random.randn(5)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 26
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('float64')"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 27
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(5,)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 28
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([          0,  -805306368,  -411821080, -1073739781], dtype=int32)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# you can be explicit about the data type that you want\n",
    "np.empty(4, dtype=np.int32)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 29
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([b'numpy', b'pandas', b'pytables'],\n",
       "      dtype='|S8')"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.array(['numpy','pandas','pytables'], dtype=np.string_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 30,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 4,  5,  0, 98], dtype=int32)"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#type casting\n",
    "float_arr = np.array([4.4, 5.52425, -0.1234, 98.1], dtype=np.float64)\n",
    "# truncate the decimal part\n",
    "float_arr.astype(np.int32)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 30,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Type casting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 30
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Since Numpy arrays are *statically typed*, the type of an array does not change once created. But we can explicitly cast an array of some type to another using the `astype` functions (see also the similar `asarray` function). This always create a new array of new type:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 30
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 2]\n",
      " [3 4]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "dtype('int64')"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print(M)\n",
    "M.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 30
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.,  2.],\n",
       "       [ 3.,  4.]])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M2 = M.astype(float)\n",
    "\n",
    "M2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 30
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('float64')"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M2.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 30,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ True,  True],\n",
       "       [ True,  True]], dtype=bool)"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M3 = M.astype(bool)\n",
    "\n",
    "M3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 30,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## File I/O"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 38
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "\n",
    "  * Loading and Storing Numpy arrays from CSV Files\n",
    "  * Loading and Storing Numpy arrays in binary format"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 39
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1800  1  1    -6.1    -6.1    -6.1 1\r\n",
      "1800  1  2   -15.4   -15.4   -15.4 1\r\n",
      "1800  1  3   -15.0   -15.0   -15.0 1\r\n",
      "1800  1  4   -19.3   -19.3   -19.3 1\r\n",
      "1800  1  5   -16.8   -16.8   -16.8 1\r\n",
      "1800  1  6   -11.4   -11.4   -11.4 1\r\n",
      "1800  1  7    -7.6    -7.6    -7.6 1\r\n",
      "1800  1  8    -7.1    -7.1    -7.1 1\r\n",
      "1800  1  9   -10.1   -10.1   -10.1 1\r\n",
      "1800  1 10    -9.5    -9.5    -9.5 1\r\n"
     ]
    }
   ],
   "source": [
    "#show first lines of file \n",
    "!head 'data/stockholm_td_adj.dat'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 40
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "#load data from csv file\n",
    "data = np.genfromtxt('data/stockholm_td_adj.dat')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 41,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(77431, 7)"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 41,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Now we can __plot__ the data using matplotlib. (for details see lecture on matplotlib)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 43,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\nYRhG4v8D4t153osryTkAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x109145080>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "fig, ax = plt.subplots(figsize=(14,4))\n",
    "ax.plot(data[:,0]+data[:,1]/12.0+data[:,2]/365, data[:,5])\n",
    "ax.axis('tight')\n",
    "ax.set_title('tempeatures in Stockholm')\n",
    "ax.set_xlabel('year')\n",
    "ax.set_ylabel('temperature (C)');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 43,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Saving a matrix as CSV\n",
    "Using `numpy.savetxt` we can store a Numpy array to a file in CSV format:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 45
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.2046,  0.6193,  0.2997],\n",
       "       [ 0.2668,  0.6211,  0.5291],\n",
       "       [ 0.1346,  0.5136,  0.1844]])"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M = np.random.rand(3,3)\n",
    "\n",
    "M"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 46
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "np.savetxt(\"random-matrix.csv\", M)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 47
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.046486340378425028e-01 6.192709663506636986e-01 2.996546736745231421e-01\r\n",
      "2.668272751028666345e-01 6.211338327692949024e-01 5.291420942770390656e-01\r\n",
      "1.345799453449335603e-01 5.135781212657464234e-01 1.844398656469152797e-01\r\n"
     ]
    }
   ],
   "source": [
    "# ! escapes a shell command. we use the linux command `cat` to display the content of the file\n",
    "!cat random-matrix.csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 48,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.20465 0.61927 0.29965\r\n",
      "0.26683 0.62113 0.52914\r\n",
      "0.13458 0.51358 0.18444\r\n"
     ]
    }
   ],
   "source": [
    "np.savetxt(\"random-matrix.csv\", M, fmt='%.5f') # fmt specifies the format\n",
    "\n",
    "!cat random-matrix.csv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 48,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Numpy's native file format"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 48
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Useful when storing and reading back numpy array data. Use the functions `numpy.save` and `numpy.load`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 51
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "random-matrix.npy: data\r\n"
     ]
    }
   ],
   "source": [
    "np.save(\"random-matrix.npy\", M)\n",
    "\n",
    "!file random-matrix.npy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 52,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "slide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.2046,  0.6193,  0.2997],\n",
       "       [ 0.2668,  0.6211,  0.5291],\n",
       "       [ 0.1346,  0.5136,  0.1844]])"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.load(\"random-matrix.npy\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 52,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Accessing Arrays - Slicing and Indexing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 54,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "\n",
    "* Numpy supports simple indexing (as in Python) \n",
    "* Additionally, fancy indexing methods \n",
    "  * Boolean indexing\n",
    "  * List indexing\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 54,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Simple Indexing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 56,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "As you expect it from Python: \n",
    "* `[idx]`\n",
    "* `[begin:end:stepsize]`\n",
    "  * Default values\n",
    "    * begin = 0\n",
    "    * end = last element\n",
    "    * stepsize = 1\n",
    "    * colons are optional\n",
    "* Negativ indizes are counted from the last element.\n",
    "  * `-i` is the short form of  `n - i` with `n` begin the number of elements in the array "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 56,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "**Examples**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 58
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.array([0, 9, 1, 4, 64])\n",
    "arr[3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 59
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([9, 1])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[1:3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 60
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 9])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr[:2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 61,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  9,  1, 55, 55])"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# set the last two elements to 55 \n",
    "arr[-2:] = 55\n",
    "arr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 61,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Indexing and Slicing with multiple dimensions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 63,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "\n",
    "\n",
    "**Indexing**\n",
    "* multidimensional indexing: selecting a particular index from a multidimensional array\n",
    "* the selection can be understood as moving along the values of the shape property\n",
    "\n",
    "**Example:** \n",
    "A 4d array `arr_4d`, with a shape of `(w,x,y,z)` will result in indexed views such that:\n",
    "\n",
    "    \n",
    "    arr_4d[i].shape == (x,y,z)\n",
    "    arr_4d[i,j].shape == (y,z)\n",
    "    arr_4d[i,j,k].shape == (z,)\n",
    "\n",
    "**Slicing**\n",
    "* slicing: selecting a subset of multidimensional arrays allows \n",
    "* For slicing you select a range of elements along a particular axis:\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 63,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "**Python Examples**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 65
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  5. ,   3. ,   4. ],\n",
       "       [  0. ,   1. ,   2. ],\n",
       "       [  1. ,   1. ,  10. ],\n",
       "       [  0. ,   0. ,   0.1]])"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr_2d = np.array([[5,3,4],[0,1,2],[1,1,10],[0,0,0.1]])\n",
    "arr_2d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 66
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 5.,  3.,  4.])"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# get the first row\n",
    "arr_2d[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 67
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 5.,  0.,  1.,  0.])"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# get the first column\n",
    "arr_2d[:,0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 68
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 5.,  3.,  4.],\n",
       "       [ 0.,  1.,  2.]])"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# get the first two rows\n",
    "arr_2d[:2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 69,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0  1  2  3  4]\n",
      " [10 11 12 13 14]\n",
      " [20 21 22 23 24]\n",
      " [30 31 32 33 34]\n",
      " [40 41 42 43 44]]\n",
      "[[11 12 13]\n",
      " [21 22 23]\n",
      " [31 32 33]]\n"
     ]
    }
   ],
   "source": [
    "A = np.array([[n+m*10 for n in range(5)] for m in range(5)])\n",
    "print (A)\n",
    "# a block from the original array\n",
    "print (A[1:4, 1:4])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 69,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Careful, it's a view!\n",
    "\n",
    "A slice does not return a copy, which means that any modifications will be\n",
    "reflected in the source array. This is a design feature of NumPy to avoid memory\n",
    "problems."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 71
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  3,  1,  4, 64])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.array([0, 3, 1, 4, 64])\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 72,
     "slide_helper": "subslide_end"
    },
    "scrolled": false,
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  3,  1, 99, 64])"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "subarr = arr[2:4]\n",
    "subarr[1] = 99\n",
    "arr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 72,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Fancy, Boolean Indexing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 74
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "\n",
    "**Boolean indexing** allows you to select data subsets of an array that satisfy a given condition.\n",
    "\n",
    "**Boolean Index Mask** defines a boolean numpy array of type `bool` where an element is selected (True) or not (False) depending on the value of the index mask at the position each element"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 75
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([10])"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#simple example\n",
    "arr = np.array([10, 20])\n",
    "idx = np.array([True, False])\n",
    "arr[idx]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 76,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.8417,  0.4801,  0.387 ,  1.2105, -0.0201])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#creating test data\n",
    "arr_2d = np.random.randn(5)\n",
    "arr_2d\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 76,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ True, False, False, False,  True], dtype=bool)"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#getting a boolean index array\n",
    "arr_2d < 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 78
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.8417, -0.0201])"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#using a boolean index array inplace\n",
    "arr_2d[arr_2d < 0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 79
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-0.0201])"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#complex boolean expressions\n",
    "arr_2d[(arr_2d > -0.5) & (arr_2d < 0)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 80,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.    ,  0.4801,  0.387 ,  1.2105,  0.    ])"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#setting the value based on a boolean indexing array\n",
    "arr_2d[arr_2d < 0] = 0\n",
    "arr_2d"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 80,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## (Fancy) list-of-locations indexing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 82
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Fancy indexing is indexing with integer arrays."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 83
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2],\n",
       "       [ 3,  4,  5],\n",
       "       [ 6,  7,  8],\n",
       "       [ 9, 10, 11],\n",
       "       [12, 13, 14],\n",
       "       [15, 16, 17]])"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#the data. 18 elements in 6 rows and 3 columns\n",
    "arr = np.arange(18).reshape(6,3)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 84
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2],\n",
       "       [12, 13, 14],\n",
       "       [12, 13, 14]])"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# fancy selection of rows in a particular order\n",
    "arr[[0,4,4]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 85
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([17, 10,  3])"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#select elements [5,2], [3,1],[1,0]\n",
    "arr[[5,3,1],[2,1,0]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 86,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "complex submatrix\n",
      " [[17 16]\n",
      " [11 10]\n",
      " [ 5  4]]\n",
      "simple submatrix\n",
      " [[17 16]\n",
      " [11 10]\n",
      " [ 5  4]]\n",
      "Cross product for N 1 D sequences\n",
      " (array([[5],\n",
      "       [3],\n",
      "       [1]]), array([[2, 1]]))\n"
     ]
    }
   ],
   "source": [
    "# select a submatrix\n",
    "print (\"complex submatrix\\n\", arr[[[5],[3],[1]],[[2,1]]])\n",
    "print (\"simple submatrix\\n\", arr[np.ix_([5,3,1],[2,1])])\n",
    "\n",
    "print (\"Cross product for N 1 D sequences\\n\", np.ix_([5,3,1],[2,1]))\n",
    "np.ix_?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 86,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Functions for extracting data from arrays and creating arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 88,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "* `where`: getting indizes from a mask \n",
    "* `diag`: extracting a diagonal matrix\n",
    "* `take`: similar to fancy indexing\n",
    "* `choose`: Constructs and array by picking elements form several arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 88,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "**where**\n",
    "\n",
    "The `where` function of Numpy returns the index of an element.\n",
    "\n",
    "Command is of form `numpy.where(array==item)`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 90
    },
    "scrolled": true,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on built-in function where in module numpy.core.multiarray:\n",
      "\n",
      "where(...)\n",
      "    where(condition, [x, y])\n",
      "    \n",
      "    Return elements, either from `x` or `y`, depending on `condition`.\n",
      "    \n",
      "    If only `condition` is given, return ``condition.nonzero()``.\n",
      "    \n",
      "    Parameters\n",
      "    ----------\n",
      "    condition : array_like, bool\n",
      "        When True, yield `x`, otherwise yield `y`.\n",
      "    x, y : array_like, optional\n",
      "        Values from which to choose. `x`, `y` and `condition` need to be\n",
      "        broadcastable to some shape.\n",
      "    \n",
      "    Returns\n",
      "    -------\n",
      "    out : ndarray or tuple of ndarrays\n",
      "        If both `x` and `y` are specified, the output array contains\n",
      "        elements of `x` where `condition` is True, and elements from\n",
      "        `y` elsewhere.\n",
      "    \n",
      "        If only `condition` is given, return the tuple\n",
      "        ``condition.nonzero()``, the indices where `condition` is True.\n",
      "    \n",
      "    See Also\n",
      "    --------\n",
      "    nonzero, choose\n",
      "    \n",
      "    Notes\n",
      "    -----\n",
      "    If `x` and `y` are given and input arrays are 1-D, `where` is\n",
      "    equivalent to::\n",
      "    \n",
      "        [xv if c else yv for (c,xv,yv) in zip(condition,x,y)]\n",
      "    \n",
      "    Examples\n",
      "    --------\n",
      "    >>> np.where([[True, False], [True, True]],\n",
      "    ...          [[1, 2], [3, 4]],\n",
      "    ...          [[9, 8], [7, 6]])\n",
      "    array([[1, 8],\n",
      "           [3, 4]])\n",
      "    \n",
      "    >>> np.where([[0, 1], [1, 0]])\n",
      "    (array([0, 1]), array([1, 0]))\n",
      "    \n",
      "    >>> x = np.arange(9.).reshape(3, 3)\n",
      "    >>> np.where( x > 5 )\n",
      "    (array([2, 2, 2]), array([0, 1, 2]))\n",
      "    >>> x[np.where( x > 3.0 )]               # Note: result is 1D.\n",
      "    array([ 4.,  5.,  6.,  7.,  8.])\n",
      "    >>> np.where(x < 5, x, -1)               # Note: broadcasting.\n",
      "    array([[ 0.,  1.,  2.],\n",
      "           [ 3.,  4., -1.],\n",
      "           [-1., -1., -1.]])\n",
      "    \n",
      "    Find the indices of elements of `x` that are in `goodvalues`.\n",
      "    \n",
      "    >>> goodvalues = [3, 4, 7]\n",
      "    >>> ix = np.isin(x, goodvalues)\n",
      "    >>> ix\n",
      "    array([[False, False, False],\n",
      "           [ True,  True, False],\n",
      "           [False,  True, False]], dtype=bool)\n",
      "    >>> np.where(ix)\n",
      "    (array([1, 1, 2]), array([0, 1, 1]))\n",
      "\n"
     ]
    }
   ],
   "source": [
    "help (np.where)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 133,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 91,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "value=17 (array([5]), array([2]))\n",
      "value>10 (array([3, 4, 4, ..., 5, 5, 5]), array([2, 0, 1, ..., 0, 1, 2]))\n"
     ]
    }
   ],
   "source": [
    "print (\"value=17\",np.where(arr==17))\n",
    "print (\"value>10\",np.where(arr>10))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 91,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "**diag**\n",
    "\n",
    "With the diag function we can also extract the diagonal and subdiagonals of an array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 134,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 93
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0  1  2]\n",
      " [ 3  4  5]\n",
      " [ 6  7  8]\n",
      " [ 9 10 11]\n",
      " [12 13 14]\n",
      " [15 16 17]]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([0, 4, 8])"
      ]
     },
     "execution_count": 134,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print (arr)\n",
    "print\n",
    "np.diag(arr)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 94,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 3,  7, 11])"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.diag(arr, -1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 94,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "**choose**\n",
    "\n",
    "Constructs and array by picking elements form several arrays as follows\n",
    "\n",
    "    np.choose(a,c) == np.array([c[a[I]][I] for I in ndi.ndindex(a.shape)])\n",
    "  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 96,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 5, -3,  6, -2])"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "which = [1, 0, 1, 0]\n",
    "choices = [[-2,-3,-2,-2], [5,5,6,5]]\n",
    "\n",
    "np.choose(which, choices)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 96,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Element assignment"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 98
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "\n",
    "We can assign new values to elements in an array using indexing techniques."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 99
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.0796  0.5052]\n",
      " [ 0.0653  0.4281]]\n",
      "[[ 1.      0.5052]\n",
      " [ 0.0653  0.4281]]\n"
     ]
    }
   ],
   "source": [
    "M = np.random.rand(2,2)\n",
    "print (M)\n",
    "M[0,0] = 1\n",
    "print\n",
    "print (M)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 100,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1.      0.5052]\n",
      " [ 0.      0.    ]]\n"
     ]
    }
   ],
   "source": [
    "# also works for rows and columns\n",
    "M[1,:] = [0, 0]\n",
    "print (M)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 100,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "**Array slices are *mutable*:**\n",
    "\n",
    "if array slices are assigned a new value the original array from which the slice was extracted is modified:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 102,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "slide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 1 -2 -3  4  5]\n"
     ]
    }
   ],
   "source": [
    "A = np.array([1,2,3,4,5])\n",
    "A[1:3] = [-2,-3]\n",
    "print (A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 102,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Operations on numpy Arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 104,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "\n",
    "* Numpy allows us to express operations without writing any for loops. These operations are key to high performance computing\n",
    "* How operations are performed depend whether we consider a multdimensional array as \n",
    "  - `ndarray`\n",
    "  - `matrix`\n",
    "  \n",
    "**Operations on matrices:** Operations on matrices follow the standard linear algebra rules.\n",
    "\n",
    "**Operations on arrays:** Operations between arrays are performed element-wise. So arrays must have the same shape. Arrays of different size are **broadcasted** to get the same size. \n",
    "Broadcasting is subject to certain constraints where the smaller array is “broadcast” across the larger array so that they have compatible shapes."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 104,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Linear Algebra and Matrix Operations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 106,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "We will take a look at\n",
    "\n",
    "  * Scalar-array operations\n",
    "  * Element-wise array operations\n",
    "  * Matrix Algebra\n",
    "  * Array/Matrix Transformations\n",
    "  * Matrix Computations\n",
    "  * Data Processing\n",
    "  * Computations on subsets of arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 106,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Scalar-array operations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 108
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "We can use the usual arithmetic operators to multiply, add, subtract, and divide arrays with scalar numbers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 109
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 1]\n"
     ]
    }
   ],
   "source": [
    "v1 = np.arange(0, 2)\n",
    "print (v1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 110
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 2])"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v1 * 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 111
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2, 3])"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    " v1 + 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 112,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[2 2]\n",
      " [4 4]]\n",
      "[[3 3]\n",
      " [4 4]]\n"
     ]
    }
   ],
   "source": [
    "#create the data first using a list\n",
    "A = np.array([[1,1],[2,2]])\n",
    "print (A * 2)\n",
    "print\n",
    "print (A + 2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 112,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Element-wise array-array operations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 114
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "When we add, subtract, multiply and divide arrays with each other, the default behaviour is **element-wise** operations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 115
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n",
      "[[1 1]\n",
      " [4 4]]\n",
      "[[1 1]\n",
      " [2 2]]\n"
     ]
    }
   ],
   "source": [
    "print (type(A))\n",
    "print (A * A) # element-wise multiplication\n",
    "print (A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 116
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1 1]\n",
      " [2 2]]\n",
      "[0 1]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[0, 1],\n",
       "       [0, 2]])"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#sizes are adjusted. that is called broadcasting and we look into this later\n",
    "print (A)\n",
    "print\n",
    "print (v1)\n",
    "A * v1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 117,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([0, 1])"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "print (type(v1))\n",
    "v1 * v1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 117,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Element-wise multiplication\n",
    "If we multiply arrays with compatible shapes, we get an element-wise multiplication of each row:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 117,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 1],\n",
       "       [4, 4]])"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A * A"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 117,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Matrix algebra"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 117
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "What about matrix mutiplication? There are two ways. We can either use the `dot` function, which applies a matrix-matrix, matrix-vector, or inner vector multiplication to its two arguments: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 122
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[3, 3],\n",
       "       [6, 6]])"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.dot(A, A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 123
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2])"
      ]
     },
     "execution_count": 67,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.dot(A, v1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 124,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.dot(v1, v1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 124,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Matrix multiplication via casts\n",
    "\n",
    "Alternatively, we can cast the array objects to the type `matrix`. This changes the behavior of the standard arithmetic operators `+, -, *` to use matrix algebra."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 124
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[0],\n",
       "        [1]])"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M = np.matrix(A)\n",
    "v = np.matrix(v1).T # make it a column vector (T is the transpose operation)\n",
    "v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 124,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.matrixlib.defmatrix.matrix'> <class 'numpy.matrixlib.defmatrix.matrix'>\n"
     ]
    }
   ],
   "source": [
    "#Note that M and v are of type matrix\n",
    "print (type(M), type(v))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 124,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[3, 3],\n",
       "        [6, 6]])"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M*M"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 129
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[1],\n",
       "        [2]])"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M*v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 130
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[1]])"
      ]
     },
     "execution_count": 73,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# inner product\n",
    "v.T * v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 131,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[1],\n",
       "        [3]])"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# with matrix objects, standard matrix algebra applies\n",
    "v + M*v"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 131,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Boundary Checks \n",
    "If we try to add, subtract or multiply objects with incomplatible shapes we get an error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 131
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "v = np.matrix([1,2,3,4,5,6]).T"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 131
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((3, 3), (6, 1))"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.shape(M), np.shape(v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 135
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "shapes (3,3) and (6,1) not aligned: 3 (dim 1) != 6 (dim 0)",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-47-995fb48ad0cc>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mM\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m/home/zieglerk/local/share/anaconda3/lib/python3.5/site-packages/numpy/matrixlib/defmatrix.py\u001b[0m in \u001b[0;36m__rmul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m    347\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    348\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__rmul__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 349\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mN\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    350\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    351\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__imul__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: shapes (3,3) and (6,1) not aligned: 3 (dim 1) != 6 (dim 0)"
     ]
    }
   ],
   "source": [
    "M * v"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 135,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "See also the related functions: `inner`, `outer`, `cross`, `kron`, `tensordot`. Try for example `help(kron)`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 135,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Array/Matrix transformations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 135
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Above we have used the `.T` to transpose the matrix object `v`. We could also have used the `transpose` function to accomplish the same thing. \n",
    "\n",
    "Other mathematical functions that transforms matrix objects are:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 139
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "C = np.matrix([[1j, 2j], [3j, 4j]])\n",
    "C"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 140,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "np.conjugate(C)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 140,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Hermitian conjugate\n",
    "   \n",
    "   * =transpose + conjugate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 140
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "C.H"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 143
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "We can extract the real and imaginary parts of complex-valued arrays using `real` and `imag`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 144
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "np.real(C) # same as: C.real"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "np.imag(C) # same as: C.imag"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "Or the complex argument and absolute value"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "np.angle(C+1) # heads up MATLAB Users, angle is used instead of arg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "np.abs(C)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145,
     "slide_helper": "subslide_end",
     "slide_type": "subslide"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Matrix Functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Inverse"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "from numpy.linalg import inv\n",
    "inv(C) # equivalent to C.I "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "C.I * C"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Determinant"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "from numpy.linalg import det\n",
    "det(C)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "det(C.I)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 145,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Broadcasting"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 157
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "\n",
    "\n",
    "Vectorized operations between arrays of different sizes and between arrays and\n",
    "scalars are subject to the rules of broadcasting. The idea is quite simple in many cases like with scalars:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 158
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([   0. ,   45. ,    5.1,   20. ,  320. ])"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.array([0, 9, 1.02, 4, 64])\n",
    "5 * arr "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 159
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 10.  ,  19.  ,  11.02,  14.  ,  74.  ])"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "10 + arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 160,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.  ,  3.  ,  1.01,  2.  ,  8.  ])"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr ** .5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 160,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Complex broadcasting rules"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 162,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "* The case of arrays of different shapes is slightly more complicated. \n",
    "* When operating on two arrays, NumPy compares their shapes element-wise. It starts with the trailing dimensions, and works its way forward. Two dimensions are compatible when\n",
    "  * they are equal, or\n",
    "  * one of them is 1\n",
    "\n",
    "see http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 162,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "#lets make a 4 row 2 column array\n",
    "arr = np.random.randn(4,2)\n",
    "arr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 164
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "#assume we know the mean over rows\n",
    "mean_row = np.array([ 0.2782,  0.4383])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 165
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# subtract the mean from the array. \n",
    "# The mean vector is automatically r times repeated with r being \n",
    "# the number of rows of arr\n",
    "centered_rows = arr - mean_row\n",
    "centered_rows"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 166,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "#now do the same via the oclumns\n",
    "mean_col = np.array([ 1.4218, -0.5382, -0.0286,  0.5779])\n",
    "mean_col"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 166,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "#Only one array gets broadcasted\n",
    "#here broadcasting does not work. \n",
    "# arr:      4 x 2\n",
    "# mean_col: 1 x 4\n",
    "centered_cols = arr - mean_col"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 168
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# make the 1-D array a column vector\n",
    "mean_col.reshape((4,1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "#Broadcasting now works\n",
    "# arr:      4 x 2\n",
    "# mean_col: 4 x 1\n",
    "centered_cols = arr - mean_col.reshape((4,1))\n",
    "centered_rows"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Data Processing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Often it is useful to store datasets in Numpy arrays. Numpy provides a number of functions to calculate statistics of datasets in arrays. \n",
    "\n",
    "For example, let's calculate some properties data from the Stockholm temperature dataset used above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(77431, 7)"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# reminder, the tempeature dataset is stored in the data variable:\n",
    "np.shape(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### mean"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6.1971096847515854"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# the temperature data is in column 3\n",
    "np.mean(data[:,3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "The daily mean temperature in Stockholm over the last 200 year so has been about 6.2 C."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### standard deviations and variance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(8.2822716213405734, 68.596023209663414)"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.std(data[:,3]), np.var(data[:,3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### min and max"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-25.800000000000001"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# lowest daily average temperature\n",
    "data[:,3].min()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "28.300000000000001"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# highest daily average temperature\n",
    "data[:,3].max()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### sum, prod, and trace"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 169
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, ..., 7, 8, 9])"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "d = np.arange(0, 10)\n",
    "d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 183,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "45"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# sum up all elements\n",
    "np.sum(d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 183,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3628800"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# product of all elements\n",
    "np.prod(d+1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 185
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0,  1,  3, ..., 28, 36, 45])"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# cummulative sum\n",
    "np.cumsum(d)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 186
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([      1,       2,       6, ...,   40320,  362880, 3628800])"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# cummulative product\n",
    "np.cumprod(d+1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 187,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "110"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "  # same as: diag(A).sum()\n",
    "np.trace(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 187,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Computations on subsets of arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 187
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "We can compute with subsets of the data in an array using indexing, fancy indexing, and the other methods of extracting data from an array (described above).\n",
    "\n",
    "For example, let's go back to the temperature dataset:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 190
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "!head -n 3 stockholm_td_adj.dat"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 191
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "The dataformat is: year, month, day, daily average temperature, low, high, location.\n",
    "\n",
    "If we are interested in the average temperature only in a particular month, say February, then we can create a index mask and use the select out only the data for that month using:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 192
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "np.unique(data[:,1]) # the month column takes values from 1 to 12"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 193
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "mask_feb = data[:,1] == 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 194,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# the temperature data is in column 3\n",
    "np.mean(data[mask_feb,3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 194,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Example: Extracting average monthly average temperatures\n",
    "With these tools we have very powerful data processing capabilities at our disposal. For example, to extract the average monthly average temperatures for each month of the year only takes a few lines of code: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 196,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "months = np.arange(1,13)\n",
    "monthly_mean = [np.mean(data[data[:,1] == month, 3]) \\\n",
    "                for month in months] \n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "ax.bar(months, monthly_mean)\n",
    "ax.set_xlabel(\"Month\")\n",
    "ax.set_ylabel(\"Monthly avg. temp.\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 196,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Calculations with higher-dimensional data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 196
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "When functions such as `min`, `max`, etc., is applied to a multidimensional arrays, it is sometimes useful to apply the calculation to the entire array, and sometimes only on a row or column basis. Using the `axis` argument we can specify how these functions should behave: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 196
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.7853,  0.854 ,  0.4942],\n",
       "       [ 0.8466,  0.0796,  0.5052],\n",
       "       [ 0.0653,  0.4281,  0.0965]])"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "m = np.random.rand(3,3)\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 200
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.85397529263948879"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# global max\n",
    "m.max()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 201
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.8466,  0.854 ,  0.5052])"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# max in each column\n",
    "m.max(axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 202
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.854 ,  0.8466,  0.4281])"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# max in each row\n",
    "m.max(axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 203,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "Many other functions and methods in the `array` and `matrix` classes accept the same (optional) `axis` keyword argument."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 203,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### A note about NANs (Not a Number) \n",
    "\n",
    "Per the floating point standard IEEE 754, NaN is a floating point value that, by definition, is not equal to any other floating point value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 205
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "np.nan == np.nan"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 206
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "#so nan checking with equals does  not work\n",
    "np.array([10,5,4,np.nan,1,np.nan]) == np.nan"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 207,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "#we need to use Numpy's isnan function\n",
    "np.isnan(np.array([10,5,4,np.nan,1,np.nan]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 207,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Reshaping, resizing and stacking arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 207
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "The shape of an Numpy array can be modified **without copying the underlaying data**, which makes it a fast operation even for large arrays.\n",
    "\n",
    "This is due to the representation of all multidimensional arrays as a one dimensional array. The shape only determines the mapping of a multidimensional coordinate on a one dimensional array."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 210
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 211
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "n, m= A.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 212
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "B = A.reshape((1,n*m))\n",
    "B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 213
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "B[0,0:5] = 5 # modify the array\n",
    "\n",
    "B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 214,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "A # and the original variable is also changed. B is only a different view of the same data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 214,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Flatten\n",
    "\n",
    "We can also use the function `flatten` to make a higher-dimensional array into a vector. But this function **creates a copy of the data**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 216
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "B = A.flatten()\n",
    "\n",
    "B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 217
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "B[0:5] = 10\n",
    "\n",
    "B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 218,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "A # now A has not changed, because B's data is a copy of A's, not refering to the same data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 218,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Adding a new dimension: newaxis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 218
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "With `newaxis`, we can insert new dimensions in an array, for example converting a vector to a column or row matrix:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 218
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "v = np.array([1,2,3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 218
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "np.shape(v)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 223
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# make a column matrix of the vector v\n",
    "v[:, newaxis]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 224
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# column matrix\n",
    "v[:,newaxis].shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "# row matrix\n",
    "v[newaxis,:].shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Stacking and repeating arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Using function `repeat`, `tile`, `vstack`, `hstack`, and `concatenate` we can create larger vectors and matrices from smaller ones:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### tile and repeat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 160,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "a = np.array([[1, 2], [3, 4]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 161,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 1, 1, ..., 4, 4, 4])"
      ]
     },
     "execution_count": 161,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# repeat each element 3 times\n",
    "np.repeat(a, 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 1, 2, 1, 2],\n",
       "       [3, 4, 3, 4, 3, 4]])"
      ]
     },
     "execution_count": 162,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# tile the matrix 3 times \n",
    "np.tile(a, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### concatenate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "b = np.array([[5, 6]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 164,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4],\n",
       "       [5, 6]])"
      ]
     },
     "execution_count": 164,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.concatenate((a, b), axis=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 165,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 5],\n",
       "       [3, 4, 6]])"
      ]
     },
     "execution_count": 165,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.concatenate((a, b.T), axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### hstack and vstack"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 166,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4],\n",
       "       [5, 6]])"
      ]
     },
     "execution_count": 166,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.vstack((a,b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 167,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2, 5],\n",
       "       [3, 4, 6]])"
      ]
     },
     "execution_count": 167,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.hstack((a,b.T))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Copy and \"deep copy\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "To achieve high performance, **assignments in Python usually do not copy the underlying objects**. This is important for example when objects are passed between functions, to avoid an excessive amount of memory copying when it is not necessary (techincal term: pass by reference). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 168,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1, 2],\n",
       "       [3, 4]])"
      ]
     },
     "execution_count": 168,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = np.array([[1, 2], [3, 4]])\n",
    "\n",
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 169,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "# now B is referring to the same array data as A \n",
    "B = A "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 170,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[10,  2],\n",
       "       [ 3,  4]])"
      ]
     },
     "execution_count": 170,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# changing B affects A\n",
    "B[0,0] = 10\n",
    "\n",
    "B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 171,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[10,  2],\n",
       "       [ 3,  4]])"
      ]
     },
     "execution_count": 171,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "If we want to avoid this behavior, so that when we get a new completely independent object `B` copied from `A`, then we need to do a so-called \"deep copy\" using the function `copy`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 172,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "B = np.copy(A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 173,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-5,  2],\n",
       "       [ 3,  4]])"
      ]
     },
     "execution_count": 173,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# now, if we modify B, A is not affected\n",
    "B[0,0] = -5\n",
    "\n",
    "B"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 174,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[10,  2],\n",
       "       [ 3,  4]])"
      ]
     },
     "execution_count": 174,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Iterating over array elements"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 225
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Generally, we want to avoid iterating over the elements of arrays whenever we can (at all costs). The reason is that in a interpreted language like Python (or MATLAB), iterations are really slow compared to vectorized operations. \n",
    "\n",
    "However, sometimes iterations are unavoidable. For such cases, the Python `for` loop is the most convenient way to iterate over an array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 175,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 251
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "v = np.array([1,2,3,4])\n",
    "\n",
    "for element in v:\n",
    "    print (element)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 176,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 252,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "row [1 2]\n",
      "1\n",
      "2\n",
      "row [3 4]\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "M = np.array([[1,2], [3,4]])\n",
    "\n",
    "for row in M:\n",
    "    print (\"row\", row)\n",
    "    \n",
    "    for element in row:\n",
    "        print (element)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 252,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### For-loops with enumerate\n",
    "When we need to iterate over each element of an array and modify its elements, it is convenient to use the `enumerate` function to obtain both the element and its index in the `for` loop: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 177,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 252
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "row_idx 0 row [1 2]\n",
      "col_idx 0 element 1\n",
      "col_idx 1 element 2\n",
      "row_idx 1 row [3 4]\n",
      "col_idx 0 element 3\n",
      "col_idx 1 element 4\n"
     ]
    }
   ],
   "source": [
    "for row_idx, row in enumerate(M):\n",
    "    print (\"row_idx\", row_idx, \"row\", row)\n",
    "    \n",
    "    for col_idx, element in enumerate(row):\n",
    "        print (\"col_idx\", col_idx, \"element\", element)\n",
    "       \n",
    "        # update the matrix M: square each element\n",
    "        M[row_idx, col_idx] = element ** 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 178,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 252,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  4],\n",
       "       [ 9, 16]])"
      ]
     },
     "execution_count": 178,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# each element in M is now squared\n",
    "M"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 252,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Vectorizing functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 252
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Another way of looping is applying a function over every element of an array. This can be done via the Numpy `vectorized` function. It can result in a slight speed improvement due to caching, but does not provide a speed improvement in general. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 179,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 258
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "def Theta(x):\n",
    "    \"\"\"\n",
    "    Scalar implemenation of the Heaviside step function.\n",
    "    \"\"\"\n",
    "    if x >= 0:\n",
    "        return 1\n",
    "    else:\n",
    "        return 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 180,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259
    },
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-180-d55419725688>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mTheta\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m<ipython-input-179-9a0cb13d93d4>\u001b[0m in \u001b[0;36mTheta\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m      3\u001b[0m     \u001b[0mScalar\u001b[0m \u001b[0mimplemenation\u001b[0m \u001b[0mof\u001b[0m \u001b[0mthe\u001b[0m \u001b[0mHeaviside\u001b[0m \u001b[0mstep\u001b[0m \u001b[0mfunction\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m     \"\"\"\n\u001b[0;32m----> 5\u001b[0;31m     \u001b[0;32mif\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      6\u001b[0m         \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      7\u001b[0m     \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"
     ]
    }
   ],
   "source": [
    "Theta(np.array([-3,-2,-1,0,1,2,3]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "OK, that didn't work because we didn't write the `Theta` function so that it can handle a vector input. \n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "#### Get a vectorized function\n",
    "To get a vectorized version of Theta we can use the Numpy function `vectorize`. In many cases it can automatically vectorize a function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 181,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "Theta_vec = np.vectorize(Theta)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 182,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 0, ..., 1, 1, 1])"
      ]
     },
     "execution_count": 182,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from array import array\n",
    "Theta_vec([-3,-2,-1,0,1,2,3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "**Using a vector-aware function**\n",
    "\n",
    "We can also implement the function to accept vector input from the beginning (requires more effort but might give better performance):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 183,
   "metadata": {
    "collapsed": true,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [],
   "source": [
    "def Theta(x):\n",
    "    \"\"\"\n",
    "    Vector-aware implemenation of the Heaviside step function.\n",
    "    \"\"\"\n",
    "    return 1 * (x >= 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 184,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 0, ..., 1, 1, 1])"
      ]
     },
     "execution_count": 184,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Theta(np.array([-3,-2,-1,0,1,2,3]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 185,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "subslide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0, 1)"
      ]
     },
     "execution_count": 185,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# still works for scalars as well\n",
    "Theta(-1.2), Theta(2.6)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Using arrays in conditions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "When using arrays in conditions in for example `if` statements and other boolean expressions, one need to use one of `any` or `all`, which requires that any or all elements in the array evalutes to `True`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 186,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  4],\n",
       "       [ 9, 16]])"
      ]
     },
     "execution_count": 186,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 187,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "at least one element in M is larger than 5\n"
     ]
    }
   ],
   "source": [
    "if (M > 5).any():\n",
    "    print (\"at least one element in M is larger than 5\")\n",
    "else:\n",
    "    print (\"no element in M is larger than 5\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 188,
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "slide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "all elements in M are not larger than 5\n"
     ]
    }
   ],
   "source": [
    "if (M > 5).all():\n",
    "    print (\"all elements in M are larger than 5\")\n",
    "else:\n",
    "    print (\"all elements in M are not larger than 5\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "heading_collapsed": false,
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Exercise"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259,
     "slide_helper": "subslide_end"
    },
    "slide_helper": "slide_end",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Conduct Exercise [DSiP-3-1 Numpy](exercises/Exercise%20DSiP-3-1-Numpy.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Appendix Volume vs. Area in high dimensions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "slideshow": {
     "slide_type": "skip"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\nggAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fcb20138cc0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import numpy as np\n",
    "from numpy.linalg import norm as d\n",
    "from matplotlib import pyplot as pl\n",
    "\n",
    "def Monte_Carlo_volume(n_dim=2, n_samples=1000):\n",
    "    points = np.random.ranf((n_samples, n_dim))-.5\n",
    "    insiders = [int(d(x)<=1) for x in points]\n",
    "    return sum(insiders)/n_samples\n",
    "\n",
    "max_dim = 25\n",
    "volumes = [Monte_Carlo_volume(n_dim=n) for n in range(1, max_dim)]\n",
    "\n",
    "pl.plot(range(1, max_dim), volumes, \".\")\n",
    "pl.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259,
     "slide_type": "subslide"
    },
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## References and further reading\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "internals": {
     "frag_helper": "fragment_end",
     "frag_number": 259
    },
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "* http://numpy.scipy.org\n",
    "* http://scipy.org/Tentative_NumPy_Tutorial\n",
    "* http://scipy.org/NumPy_for_Matlab_Users - A Numpy guide for MATLAB users.\n",
    "- William Wesley McKinney. Python for Data Analysis. O’Reilly, 2012."
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  },
  "toc": {
   "colors": {
    "hover_highlight": "#DAA520",
    "running_highlight": "#FF0000",
    "selected_highlight": "#FFD700"
   },
   "moveMenuLeft": true,
   "nav_menu": {
    "height": "512px",
    "width": "252px"
   },
   "navigate_menu": true,
   "number_sections": true,
   "sideBar": true,
   "threshold": 4,
   "toc_cell": false,
   "toc_section_display": "block",
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
